﻿"""
requests 最流行的请求库  依赖于urllib3（urllib的升级；无论是urllib还是urllib3都不需要安装了，python自带的）

状态码：
    请求成功 200
    不成功 404
    415  请求类型错误

响应内容
    1.text 编码为空（无法使用decode解码）
        当后端使用encode编码时，text就无法解析了
    2.content 当text解码失败时，就需要使用content自己设置解码方式
        注意 1.解码要和编码的方式一致  2.使用content解析文本内容需要解码
    text、content默认使用utf-8解码
    3.json  text返回的是一个字符串，无法使用字典的方式获取内容（res.json()["info"]）
            content返回的是一个字节流，无法直接查看内容，所以使用json解析

    注意：即使后端设置的返回数据是一个json但是请求头中的类型仍然是text/html;
        因为后端模拟使用的是python自带的json库（return json.dumps({"info": "天官赐福"})）

        后端设置的json使用的是flask框架中的jsonify（return jsonify({"info": "天官赐福"})）
        返回的类型是application/json

        =============================================================

        后端模拟设置"天官赐福 百无禁忌".encode(encoding="GBK")，获取的编码为utf-8
        使用Response设置规定编码为GBK，此时获取的编码为gbk
        Response("天官赐福 百无禁忌".encode(encoding="GBK"), content_type="text/html; charset=gbk")

    先用text再用content.decode

参数：1.get
        参数有两种方法：1.直接在请求的后面用?拼接
        2.使用params传递

        原始请求：http://127.0.0.1:5000/params
        1.请求：res = requests.get("http://127.0.0.1:5000/params?page=1&size=10")
        参数：page=1  size=10
        2.请求：res = requests.get("http://127.0.0.1:5000/params", params={"next": "/center"})
        参数：next=/center

        服务器接收了爬虫传输的数据，然后进行了返回
        发起请求时get的参数需要能在服务器中进行解析
        解析方式:
            库==> flask有一个全局对象request
                from flask import request
            获取参数：  request.args.get("参数名", 默认值)
                    page = request.args.get("page", 1)

    2.post
        数据分为data和json，其请求头的类型不一样
            data：multipart/form-data
            json：application/json
        两个请求头中data和json只能有一个

        post请求中只要带有data参数，那么请求头的类型（默认）就是application/x-www-form-urlencoded
        json参数的请求头类型就是application/json

        注：！！！！发起post请求时一定要注意请求头所携带的参数是data还是json
"""

import requests


def get_status():
    """
    url ==> 自己编写的flask模拟项目
    获取状态码 ==> 请求成功：200
    """

    # 发起请求
    res = requests.get("http://127.0.0.1:5000/")
    # 错误请求 ==> 状态码 404
    res = requests.get("http://127.0.0.1:5000/abc")

    # 状态码
    # print(res)  # <Response [200]>
    # 更详细的
    # print(res.status_code, type(res.status_code))  # 200  <class 'int'>

    if res.status_code == 200:
        # print(res.text)  # <h4>后端反爬模拟</h4>
        # print(res.content)  # b'<h4>\xe5\x90\x8e\xe7\xab\xaf\xe5\x8f\x8d\xe7\x88\xac\xe6\xa8\xa1\xe6\x8b\x9f</h4>'
        # print(res.json())  # 报错
        print(f"请求成功，状态码：{res.status_code}")  # 请求成功，状态码：200
    else:
        print(f"请求失败，状态码：{res.status_code}")  # 请求失败，状态码：404


def get_response():
    """
    响应内容：text、content、json

    使用text为后端编码为空（无法解码）
        当后端使用encode编码时，text就无法解析了
    需要使用content，注：1.解码要和编码的方式一致
                    2.使用content解析文本内容需要解码
    text、content默认使用utf-8解码
    """
    # 发起请求
    res = requests.get("http://127.0.0.1:5000/response_type")

    if res.status_code == 200:
        # 后端模拟返回"天官赐福 百无禁忌"
        # print(res.text)  # 天官赐福 百无禁忌
        # # 使用content解析文本内容需要解码
        # print(res.content.decode())  # 天官赐福 百无禁忌
        # # text默认使用utf-8解码,当解码失败时，就需要使用content自己解码

        # # 后端模拟返回"天官赐福 百无禁忌".encode(encoding="GBK")
        # print(res.text)  # 乱码
        # # 因为text无法解析，所以需要自己解码使用content
        # print(res.content.decode(encoding="GBK"))  # 天官赐福 百无禁忌

        # # 后端：json.dumps({"info": "天官赐福"})
        # print(res.text)  # {"info": "\u5929\u5b98\u8d50\u798f"}
        # # 无法使用["info"]，因为text是一个字符串（即使返回类型是application）
        # print(res.content.decode(encoding="GBK"))  # {"info": "\u5929\u5b98\u8d50\u798f"}
        # # 跟text一样
        # print(res.json())  # {'info': '天官赐福'}
        # # 可以使用["info"]
        # print(res.json()["info"])   # 天官赐福

        # # 即使后端设置的返回数据是一个json但是请求头中的类型仍然是text/html; charset=utf-8
        # # 使用的是python自带的json库
        # # return json.dumps({"info": "天官赐福"})
        # print(res.headers["Content-Type"])  # text/html; charset=utf-8

        # # 此时后端设置的json使用的是flask框架中的jsonify
        # # return jsonify({"info": "天官赐福"})
        # # 返回的类型是application/json
        # print(res.headers["Content-Type"])  # application/json

        # 无法获取编码
        # "天官赐福 百无禁忌".encode(encoding="GBK")
        # print(res.encoding)  # utf-8
        # 后端返回的是gbk格式的字符串
        # Response("天官赐福 百无禁忌".encode(encoding="GBK"), content_type="text/html; charset=gbk")
        print(res.encoding)  # gbk


def get_params():
    """
    发起请求

    参数有两种方法：1.直接在请求的后面用?拼接
    2.使用params传递

    原始请求：http://127.0.0.1:5000/params
    1.请求：res = requests.get("http://127.0.0.1:5000/params?page=1&size=10")
    2.请求：res = requests.get("http://127.0.0.1:5000/params", params={"next": "/center"})

    """
    # # res = requests.get("http://127.0.0.1:5000/params")
    # # get请求的参数可以在?后进行拼接
    # res = requests.get("http://127.0.0.1:5000/params?page=1&size=10")
    #
    # # jsonify({"code": 0})
    # # 使用的jsonify，所以解析时可以直接使用json
    # # print(res.json())  # {"code": 0}
    #
    # # 带参数的
    # # print(res.json())  # {'args': {'page': '1', 'size': '10'}, 'code': 0}
    #
    # # result = {
    # #     "code": 0,
    # #     "args": {
    # #         "page": page,
    # #         "size": size
    # #     },
    # #     "header": {
    # #         "User-Agent": request.headers["User-Agent"]
    # #     }
    # # }
    # print(res.json())  # {'args': {'page': '1', 'size': '10'}, 'code': 0, 'header': {'User-Agent':
    # # 'python-requests/2.31.0'}}

    # ============================================================================================
    # params参数
    res = requests.get("http://127.0.0.1:5000/params?page=1&size=10", params={
        "type": "views",
        "sort": "id",
        "limit": 50
    })
    print(res.json())  # {'args': {'next': '/center', 'page': '1', 'size': '10'}, 'code': 0, 'header': {'User-Agent':
    # 'python-requests/2.31.0'}}


# post请求=================================================================================================
def get_data():
    """
    发起post请求
    数据分为data和json，其请求头的类型不一样
        data：multipart/form-data
        json：application/json

    带有data参数的默认请求头的content-type是application/x-www-form-urlencoded
    """
    res = requests.post("http://127.0.0.1:5000/data", data={
        "name": "admin",
        "password": "123456"
    })
    # 添加json解析会报错因为此时默认的请求头中content-type是application/x-www-form-urlencoded
    # print(res.json())
    print(res.request.headers["Content-Type"], res.json())


def get_json():
    """
    在post请求中使用json参数
    默认请求头的content-type是application/json

    如果在data路径下携带json参数，那么服务器将不会识别json中的参数
    """
    res = requests.post("http://127.0.0.1:5000/json", json={
        "name": "admin",
        "password": "123456"
    })
    print(res.request.headers["Content-Type"], res.json())
    # application/json {'code': 0, 'headers': {'User-Agent': 'python-requests/2.31.0'}, 'json': {'name': 'admin',
    # 'password': '123456'}}


if __name__ == '__main__':
    # 先运行模拟的后端再运行请求
    # get_status()
    # 状态码200时请求成功才能解析

    # 响应内容：text、content、json
    # get_response()

    # get请求参数
    # get_params()

    # post请求
    # get_data()
    get_json()
